﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Net;
using System.Net.Sockets;
using System.Threading;

using eLibCommon;

namespace eLibServer.Core
{
  public class ConnectionHandler
  {
    // http://www.ziggyware.com/readarticle.php?article_id=133&rowstart=1

    private List<ClientHandler> _clientList = new List<ClientHandler>();    
    private TcpListener _listener;
    private bool _listenerActive;

    public event OnConnectionAcceptedHandler OnConnectionAccepted;
    public event OnStartListeningHandler OnStartListening;
    public event OnStopListeningHandler OnStopListening;
    public event OnClientDisconnectHandler OnConnectionClosed;

    public ConnectionHandler()
    {

    }

    public void StartListening(int port)
    {
      this.CleanupListener();

      _listener = new TcpListener(new IPEndPoint(IPAddress.Any, port));
      _listener.Start();
      _listenerActive = true;
     
      if (OnStartListening != null)
        OnStartListening(this, new StartListeningEventArgs(port));
      
      _listener.BeginAcceptTcpClient(new AsyncCallback(this.AcceptTcpClientComplete), null);
    }
                                                        
    public void StopListening()
    {
      CleanupListener();
      _listener.Stop();
      _listenerActive = false;
      _clientList.Clear();
      if (OnStopListening != null)
        OnStopListening(this, EventArgs.Empty);
    }

    private void CleanupListener()
    {
      if (_listener == null)
        return;

      if (_listener.Server.Connected)
        _listener.Server.Disconnect(true);

      _listener.Server.Close();
    }

    private void AcceptTcpClientComplete(IAsyncResult ar)
    {
      // When you stop the listener it sends a request to disconnect and 
      // receiving an "ACK" from the connection.
      string receiveString = string.Empty;
      try
      {
        TcpClient client = _listener.EndAcceptTcpClient(ar);
        IPEndPoint clientEndPoint = (IPEndPoint)client.Client.RemoteEndPoint;

        //ClientHandler clientHandler = _clientList.Find(x => x.ClientEndPoint.Address == clientEndPoint.Address);
        ClientHandler clientHandler = null;
        if (clientHandler == null)
        {
          clientHandler = new ClientHandler(client);                   
          _clientList.Add(clientHandler);

          clientHandler.OnClientDisconnect += new OnClientDisconnectHandler(OnClientDisconnect); 

          Thread t = new Thread(new ThreadStart(clientHandler.ThreadStartProc));
          t.Start();

          if (OnConnectionAccepted != null)
            OnConnectionAccepted(this, new ConnectionAcceptedEventArgs(clientEndPoint) );
        }
      }
      catch (ObjectDisposedException)
      {

      }
      finally
      {
        if (_listenerActive)
          _listener.BeginAcceptTcpClient(new AsyncCallback(this.AcceptTcpClientComplete), new object());  
      }

    }

    private void OnClientDisconnect(object sender, OnClientDisconnectEventArgs e)
    {
      //_clientList.RemoveAll(x => x.ClientEndPoint.Address == e.RemoteEndPoint.Address);

      if (this.OnConnectionClosed != null)
        this.OnConnectionClosed(this, e);
    }



    

    
  }
}


  

